`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/02/01 09:02:21
// Design Name: 
// Module Name: phy_mdio
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module phy_mdio(
    input clk,
    input rst,          // Active low
    
    output reg mdc,     // Max 12M
    output wire mdi,
    input wire mdo,
    output wire mdio_ctr,    // 1: mdo valid  0: mdi valid

    input [4:0] phy_id,
    input [4:0] reg_id,

    input  wire wr,
    input [15:0] send_data,
    input send_data_vld,
    output [15:0] recv_data,
    output reg wr_done
    );


wire [45:0] first_data;
wire [1:0] op_wr;
wire [17:0] wr_data;

assign op_wr = (wr == 1'b0)? 2'b01: 2'b10;  //2'b01 : Write  2'b10 : Read
assign first_data = {32'b1111_1111_1111_1111_1111_1111_1111_1111,2'b01,op_wr[1:0],phy_id[4:0],reg_id[4:0]};
assign wr_data = {2'b10,send_data[15:0]};


reg mdi_reg;
reg [4:0] st_state;

reg io_ctr;

reg [7:0] clk_div;
reg [7:0] cnt;

reg [17:0] rd_data;
// reg rd_data_vld;

always @ (posedge clk or negedge rst)
    begin
    if(!rst)
        begin
        mdc <= 1'b0;
        mdi_reg <= 1'b1;        // 空闲时上拉MDIO 作为三态输入
        io_ctr <= 1'b1;         // 空闲时上拉MDIO 作为三态输入
        rd_data <= 18'b0;
        wr_done <= 1'b0;
        clk_div <= 8'b0;
        cnt <= 8'b0;
        st_state <= 5'd0;
        end
    else case (st_state)
        5'd0:   // 空闲状态，等待指令
            begin
            mdc <= 1'b0;
            mdi_reg <= 1'b1;
            // rd_data <= 18'b0;
            wr_done <= 1'b0;
            clk_div <= 8'b0;
            cnt <= 8'b0;
            if(send_data_vld)    //  Write Instruction
                begin
                st_state <= st_state + 1'b1;
                io_ctr <= 1'b0;
                // mdi_reg <= 1'b0;
                end
            else 
                begin
                io_ctr <= 1'b1;
                end
            end

        5'd1:   // 发送前46bit指令
            begin
            mdc <= 1'b0;
            mdi_reg <= first_data[45-cnt];
            if(clk_div == 8'd15)
                begin
                clk_div <= 8'b0;
                cnt <= cnt + 1'b1;
                st_state <= st_state + 1'b1;
                end
            else 
                begin
                clk_div <= clk_div + 1'b1;
                end            
            end
        5'd2:   // 发送前46bit指令
            begin
            mdc <= 1'b1;
            if(clk_div == 8'd15)
                begin
                clk_div <= 8'b0;
                if(cnt == 8'd46)
                    begin
                    cnt <= 8'b0;
                    if(wr == 1'b0)  // Write mdio
                        begin
                        st_state <= st_state + 1'b1;
                        io_ctr <= 1'b0;
                        end
                    else            // Read mdio
                        begin
                        st_state <= 5'd5;
                        io_ctr <= 1'b1;
                        end
                    end
                else
                    begin
                    st_state <= st_state - 1'b1;
                    end
                end
            else
                begin
                clk_div <= clk_div + 1'b1;
                end
            end
        5'd3:   // Write mdio
            begin
            mdc <= 1'b0;
            mdi_reg <= wr_data[17-cnt];
            if(clk_div == 8'd15)
                begin
                clk_div <= 8'd0;
                cnt <= cnt + 1'b1;
                st_state <= st_state + 1'b1;
                end
            else
                begin
                clk_div <= clk_div + 1'b1;
                end
            end
        5'd4:   // Write mdio
            begin
            mdc <= 1'b1;            
            if(clk_div == 8'd15)
                begin
                clk_div <= 8'b0;
                if(cnt == 8'd18)
                    begin
                    cnt <= 8'b0;
                    st_state <= 8'd7;
                    end
                else
                    begin
                    st_state <= st_state - 1'b1;
                    end
                end
            else
                begin
                clk_div <= clk_div + 1'b1;
                end
            end
        5'd5:   // Read mdio
            begin
            mdc <= 1'b0;
            if(clk_div == 8'd15)
                begin
                clk_div <= 8'b0;
                cnt <= cnt + 1'b1;
                st_state <= st_state + 1'b1;
                end
            else
                begin
                clk_div <= clk_div + 1'b1;
                if(clk_div == 8'd7)
                    begin
                    rd_data[17-cnt] <= mdo;
                    end 
                end
            end
        5'd6:   // Read mdio
            begin
            mdc <= 1'b1;
            if(clk_div == 8'd15)
                begin
                clk_div <= 8'b0;
                if(cnt == 8'd18)
                    begin
                    st_state <= 5'd7;
                    cnt <= 8'd0;
                    end
                else
                    begin
                    st_state <= st_state - 1'b1;
                    end
                end
            else
                begin
                clk_div <= clk_div + 1'b1;
                // if(clk_div == 8'd7)
                //     begin
                //     rd_data[18-cnt] <= mdo;
                //     end 
                end
            end
        5'd7:
            begin
            mdc <= 1'b0;
            wr_done <= 1'b1;
            st_state <= st_state + 1'b1;
            end
        5'd8:
            begin
            mdc <= 1'b0;
            // rd_data <= 18'b0;
            wr_done <= 1'b0;
            st_state <= 5'd0;
            end
        default :
            begin
            mdc <= 1'b0;
            mdi_reg <= 1'b1;        // 空闲时上拉MDIO 作为三态输入
            io_ctr <= 1'b1;         // 空闲时上拉MDIO 作为三态输入
            rd_data <= 18'b0;
            wr_done <= 1'b0;
            clk_div <= 8'b0;
            cnt <= 8'b0;
            st_state <= 5'd0;
            end
    endcase
    end


        
assign mdi = mdi_reg;
assign mdio_ctr = io_ctr;
assign recv_data = rd_data[15:0];

// ila_2 MDIO_ILA (
// 	.clk(clk), // input wire clk
// 	.probe0(mdc), // input wire [0:0]  probe0  
// 	.probe1(mdo), // input wire [0:0]  probe1 
// 	.probe2(mdi), // input wire [0:0]  probe2 
// 	.probe3(io_ctr), // input wire [0:0]  probe3 
// 	.probe4(send_data), // input wire [15:0]  probe4 
// 	.probe5(send_data_vld), // input wire [0:0]  probe5 
// 	.probe6(wr), // input wire [0:0]  probe6 
// 	.probe7(wr_done), // input wire [0:0]  probe7 
// 	.probe8(recv_data), // input wire [15:0]  probe8 
// 	.probe9(st_state), // input wire [4:0]  probe9 
// 	.probe10(first_data), // input wire [45:0]  probe10 
// 	.probe11(1'b0) // input wire [0:0]  probe11
// );


endmodule
